// list.go
package main

import (
	"fmt"
)

type DrList struct {
	DrVarObject
	class  *DrClass
	cursor int
}

func NewList(objects []IObject) *DrList {
	list := new(DrList)
	list.Elements = objects
	list.Type = TypeList
	list.members = make(map[string]IObject)
	list.members["append"] = NewFunction("append", []string{"obj"})
	list.members["pop"] = NewFunction("pop", nil)
	return list
}
func CreateListFromParam(params []IObject) *DrList {
	if len(params) == 1 { //如果仅有一个参数
		result := make([]IObject, 0, 10)
		prm, ok := params[0].(IIterable) //看它是否可迭代
		if ok {
			prm.ResetCursor()
			for {
				ob := prm.Next()
				if ob == nil {
					break
				}
				result = append(result, ob)

			}
			return NewList(result)
		} else {
			result := []IObject{params[0]}
			return NewList(result)
		}
	}

	Elements := make([]IObject, 0, 100)
	for i := 0; i < len(params); i++ {
		para0 := params[i]
		if para0.getType() == TypeNumArray {
			arr := para0.(*DrNumArray)
			n := len(arr.data)
			elements := make([]IObject, 0, 40)
			if len(arr.dims) == 1 {

				for i := 0; i < n; i++ {
					numOb := NewNum(arr.data[i])
					elements = append(elements, numOb)
				}
				Elements = append(Elements, NewList(elements))
			} else if len(arr.dims) == 2 {
				rows := arr.dims[0]
				cols := arr.dims[1]
				bigList := make([]IObject, 0, rows)
				for row := 0; row < rows; row++ {
					elements := make([]IObject, 0, cols)
					for col := 0; col < cols; col++ {
						numOb := NewNum(arr.Get2dValue(row, col))
						elements = append(elements, numOb)
					}
					list := NewList(elements)
					bigList = append(bigList, list)

				}
				Elements = append(Elements, NewList(bigList))
			}
		} else {
			Elements = append(Elements, para0)
		}
	}
	return NewList(Elements)
}
func (self *DrList) getType() DataType {
	return self.Type
}

func (self *DrList) getValue() float64 {
	panic("Only used for simple object such as int and float")
}

func (self *DrList) Copy() *DrList {
	tuple := new(DrList)
	copy(tuple.Elements, self.GetElems())

	tuple.Type = TypeList
	return tuple
}

func (self *DrList) getValueAt(index int) IObject {
	return self.GetElems()[index]
}
func (self *DrList) AsString() string {
	data := self.GetElems()
	s := "["
	for _, v := range data {
		s = s + " " + v.AsString() + ","
	}
	s += "]"
	return s
}
func (self *DrList) Print(interp *Interpreter) {
	if interp.hasPrinted(self) {
		fmt.Print("[...]")
	} else {
		interp.PrintSet[self] = 1 //如果已打印过了，就不能再递归打印了
		fmt.Print("[")
		data := self.GetElems()
		for _, v := range data {
			v.Print(interp)
			fmt.Print(",")
		}
		fmt.Print("]")
	}
}
func (self *DrList) Append(ob IObject) {
	self.Elements = append(self.GetElems(), ob)

}
func (self *DrList) Pop() IObject {
	top := self.GetElems()[len(self.GetElems())-1]
	self.Elements = self.GetElems()[:self.Len()-1]
	return top
}
func (self *DrList) ToTuple() *DrTuple {

	tp := NewTuple(self.GetElems())
	copy(tp.Elements, self.GetElems())

	return tp
}
func (self *DrList) ToArray2(rows int, cols int) IObject {
	if rows*cols != self.Len() {
		panic("data length is incorrect")
	}
	mat := NewNumArray2d(rows, cols)

	n := self.Len()
	for i := 0; i < n; i++ {
		elem := self.GetElems()[i]
		v := elem.getDouble()
		mat.data[i] = v
	}
	return mat

}
func (self *DrList) ToArray1() *DrNumArray {

	n := self.Len()
	mat := NewNumArray2d(1, n)

	for i := 0; i < n; i++ {
		elem := self.GetElems()[i]
		var v float64
		if elem.getType() == TypeInt {
			v = elem.(*DrInt).AsFloat()
		} else if elem.getType() == TypeNum {
			v = elem.getDouble()
		}
		mat.data[i] = v
	}
	return mat

}
func (self *DrList) Extend(ob IObject) {

	if ob.getType() == TypeList {
		data1, _ := ob.(*DrList)
		self.Elements = append(self.Elements, data1.GetElems()...)

	} else if ob.getType() == TypeTuple {
		data1, _ := ob.(*DrTuple)
		self.Elements = append(self.Elements, data1.GetElems()...)
	}
}
func (self *DrList) Next() IObject {
	if self.cursor == self.Len() {
		return nil
	}
	result := self.GetElems()[self.cursor]
	self.cursor += 1
	return result
}
func (self *DrList) ResetCursor() {
	self.cursor = 0
}
func (self *DrList) executeMethod(funcName string, prams []IObject) IObject {

	if funcName == "append" {
		self.Append(prams[1])
		return prams[0]
	}
	if funcName == "pop" {
		return self.Pop()
	}
	if funcName == "extend" {
		self.AddList(prams[1])
	}
	panic("funcName is inexist for this object")

}
func (self *DrList) getMembers() map[string]IObject {
	return self.members
}
func (self *DrList) AddList(ob IObject) IObject {

	result := NewList(self.GetElems())
	if ob.getType() == TypeList {
		data1, _ := ob.(*DrList)
		result.Elements = append(result.Elements, data1.Elements...)

	} else if ob.getType() == TypeTuple {
		data1, _ := ob.(*DrTuple)
		result.Elements = append(result.Elements, data1.GetElems()...)
	} else {
		panic("not supported now")
	}

	return result
}
